<?php

namespace App\Controller\Admin;

use App\Constants\ErrorCode;
use App\Constants\RedisKey;
use App\Middleware\AdminMiddleware;
use App\Model\AdminAuthGroupAccess;
use App\Model\AdminUser;
use App\Model\AdminUserData;
use App\Service\ToolService;
use Hyperf\Context\ApplicationContext;
use Hyperf\DbConnection\Db;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Hyperf\HttpServer\Annotation\Middleware;
use Hyperf\HttpServer\Annotation\PostMapping;
use Hyperf\Redis\RedisFactory;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use function Hyperf\Config\config;

#[Controller(prefix: '/admin/User'), Middleware(AdminMiddleware::class)]
class UserController extends BaseController {
    /**
     * 获取用户列表
     * @return array
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    #[GetMapping(path: 'index')]
    public function index(): array {
        $limit = $this->request->query('size', config('apiadmin.admin_list_default'));
        $type = $this->request->query('type', '');
        $keywords = $this->request->query('keywords', '');
        $status = $this->request->query('status', '');

        $obj = AdminUser::query();
        if (strlen($status)) {
            $obj = $obj->where('status', $status);
        }
        if ($type) {
            switch ($type) {
                case 1:
                    $obj = $obj->where('username', 'like', "%{$keywords}%");
                    break;
                case 2:
                    $obj = $obj->where('nickname', 'like', "%{$keywords}%");
                    break;
            }
        }

        $listObj = $obj->orderByDesc('create_time')->paginate($limit);
        $listInfo = $listObj->items();
        $idArr = array_column(ToolService::buildArrFromObj($listInfo), 'id');

        $userGroup = AdminAuthGroupAccess::query()->whereIn('uid', $idArr)->get();
        $userGroup = ToolService::buildArrFromObj($userGroup);
        $userGroup = ToolService::buildArrByNewKey($userGroup, 'uid');

        $newList = [];
        foreach ($listInfo as $key => $value) {
            $value->userData;
            $value = $value->toArray();

            if (!empty($value['user_data'])) {
                $value['user_data']['last_login_ip'] = long2ip($value['user_data']['last_login_ip']);
                $value['user_data']['last_login_time'] = date('Y-m-d H:i:s', $value['user_data']['last_login_time']);
                $value['create_ip'] = long2ip($value['create_ip']);
            }
            if (isset($userGroup[$value['id']])) {
                $value['group_id'] = explode(',', $userGroup[$value['id']]['group_id']);
            } else {
                $value['group_id'] = [];
            }
            $newList[$key] = $value;
        }

        return $this->buildSuccess([
            'list'  => $newList,
            'count' => $listObj->total()
        ]);
    }

    /**
     * 新增用户
     * @return array
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    #[PostMapping(path: 'add')]
    public function add(): array {
        $groups = '';
        $postData = $this->request->post();
        $postData['create_ip'] = sprintf("%u", ip2long($this->getIp()));
        $postData['password'] = ToolService::userMd5($postData['password']);
        if (isset($postData['group_id']) && $postData['group_id']) {
            $groups = trim(implode(',', $postData['group_id']), ',');
            unset($postData['group_id']);
        }

        $postData = $this->filterData((new AdminUser())->getTable(), $postData);
        $uid = AdminUser::insertGetId($postData);
        AdminAuthGroupAccess::insert([
            'uid'      => $uid,
            'group_id' => $groups
        ]);
        AdminUserData::insert([
            'uid'        => $uid
        ]);

        return $this->buildSuccess();
    }

    /**
     * 获取当前组的全部用户
     * @return array
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    #[GetMapping(path: 'getUsers')]
    public function getUsers(): array {
        $limit = $this->request->query('size', config('apiadmin.admin_list_default'));
        $page = $this->request->query('page', 1);
        $gid = $this->request->query('gid', 0);
        if (!$gid) {
            return $this->buildFailed(ErrorCode::PARAM_INVALID, '非法操作');
        }

        $totalNum = AdminAuthGroupAccess::query()->whereRaw('FIND_IN_SET(?, group_id)', [$gid])->count();
        $start = $limit * ($page - 1);

        $sql = "SELECT au.* FROM admin_user as au LEFT JOIN admin_auth_group_access as aaga " .
            " ON aaga.`uid` = au.`id` WHERE find_in_set('{$gid}', aaga.`group_id`) " .
            " ORDER BY au.create_time DESC LIMIT {$start}, {$limit};";
        $userInfo = Db::select($sql);

        if (!empty($userInfo)) {
            $uidArr = array_column($userInfo, 'id');
            $userData = AdminUserData::query()->whereIn('uid', $uidArr)->get();
            $userData = ToolService::buildArrFromObj($userData, 'uid');

            foreach ($userInfo as $key => $value) {
                if (isset($userData[$value->id])) {
                    $value->last_login_ip = long2ip($userData[$value->id]['last_login_ip']);
                    $value->login_times = $userData[$value->id]['login_times'];
                    $value->last_login_time = date('Y-m-d H:i:s', $userData[$value->id]['last_login_time']);
                }
                $value->create_ip = long2ip($value->create_ip);
                $userInfo[$key] = $value;
            }
        } else {
            $userInfo = [];
        }

        return $this->buildSuccess([
            'list'  => $userInfo,
            'count' => $totalNum
        ]);
    }

    /**
     * 用户状态编辑
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    #[GetMapping(path: 'changeStatus')]
    public function changeStatus(): array {
        $id = $this->request->query('id');
        $status = $this->request->query('status');

        AdminUser::query()->where('id', $id)->update(['status' => $status]);
        $this->logoutUser($id);

        return $this->buildSuccess();
    }

    /**
     * 编辑用户
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    #[PostMapping(path: 'edit')]
    public function edit(): array {
        $groups = '';
        $postData = $this->request->post();
        if ($postData['password'] === 'ApiAdmin') {
            unset($postData['password']);
        } else {
            $postData['password'] = ToolService::userMd5($postData['password']);
        }
        if (isset($postData['group_id']) && $postData['group_id']) {
            $groups = trim(implode(',', $postData['group_id']), ',');
            unset($postData['group_id']);
        }
        $updateData = $this->filterData((new AdminUser())->getTable(), $postData);
        AdminUser::query()->where('id', $postData['id'])->update($updateData);

        $has = AdminAuthGroupAccess::query()->where('uid', $postData['id'])->count();
        if ($has) {
            AdminAuthGroupAccess::query()->where('uid', $postData['id'])->update([
                'group_id' => $groups
            ]);
        } else {
            AdminAuthGroupAccess::insert([
                'uid'      => $postData['id'],
                'group_id' => $groups
            ]);
        }

        $this->logoutUser($postData['id']);

        return $this->buildSuccess();
    }

    /**
     * 修改自己的信息
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    #[PostMapping(path: 'own')]
    public function own(): array {
        $userDataArr = $this->uInfo();
        $postData = $this->request->post();
        $headImg = $postData['head_img'];

        if ($postData['password'] && $postData['oldPassword']) {
            $oldPass = ToolService::userMd5($postData['oldPassword']);
            unset($postData['oldPassword']);
            if ($oldPass === $userDataArr['password']) {
                $postData['password'] = ToolService::userMd5($postData['password']);
            } else {
                return $this->buildFailed(ErrorCode::INVALID, '原始密码不正确');
            }
        } else {
            unset($postData['password']);
            unset($postData['oldPassword']);
        }
        $postData['id'] = $userDataArr['id'];
        unset($postData['head_img']);

        $updateData = $this->filterData((new AdminUser())->getTable(), $postData);
        AdminUser::query()->where('id', $postData['id'])->update($updateData);

        $userData = AdminUserData::query()->where('uid', $postData['id'])->first();
        if (!empty($userData)) {
            $userData->head_img = $headImg;
            $userData->save();
        }
        $this->logoutUser($postData['id']);

        return $this->buildSuccess();
    }

    /**
     * 删除用户
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    #[GetMapping(path: 'del')]
    public function del(): array {
        $id = $this->request->query('id');
        if (!$id) {
            return $this->buildFailed(ErrorCode::EMPTY_PARAMS, '缺少必要参数');
        }

        $isAdmin = ToolService::isAdministrator($id);
        if ($isAdmin) {
            return $this->buildFailed(ErrorCode::INVALID, '超级管理员不能被删除');
        }
        AdminUser::destroy($id);
        AdminAuthGroupAccess::query()->where('uid', $id)->delete();
        $this->logoutUser($id);

        return $this->buildSuccess();
    }

    /**
     * 退出用户
     * @param $uid
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    private function logoutUser($uid): void {
        $redis = ApplicationContext::getContainer()->get(RedisFactory::class)->get('default');
        $apiAuth = $redis->get(RedisKey::ADMIN_LOGIN_ID . ':' . $uid);
        if ($apiAuth) {
            $redis->del(RedisKey::ADMIN_LOGIN_AUTH . ':' . $apiAuth);
            $redis->del(RedisKey::ADMIN_LOGIN_ID . ':' . $uid);
        }
    }
}
